/**
 * 全局 WebSocket 服务（单例模式）
 * 
 * 用途：
 * 1. 系统消息推送：如点赞通知、评论通知等
 * 2. 实时通知：系统公告、活动通知等
 * 3. 全局状态同步：用户状态变更、数据更新等
 * 
 * 特点：
 * - 单例模式：整个应用只有一个全局 WebSocket 连接
 * - 自动管理：登录时自动连接，登出时自动断开
 * - 消息路由：支持按消息类型注册不同的处理器
 */
import { createWebSocketClient } from '@/utils/websocket'

class WebSocketService {
  constructor() {
    this.client = null                    // WebSocket 客户端实例
    this.messageHandlers = new Map()      // 消息类型处理器映射表（key: 消息类型, value: 处理器数组）
    this.connectionListeners = []         // 连接状态监听器数组（用于监听连接状态变化）
  }

  /**
   * 初始化全局 WebSocket 连接
   * 
   * 说明：
   * - 只有在用户已登录时才初始化（需要 user_id）
   * - 如果已有连接，先断开再重新连接（确保连接是最新的）
   * - 注册所有事件处理器，建立完整的消息处理链路
   */
  init() {
    // 检查用户是否已登录（需要 user_id 才能建立连接）
    const userId = localStorage.getItem('user_id')
    if (!userId) {
      console.log('[WebSocketService] 用户未登录，跳过 WebSocket 初始化')
      return
    }
    
    // 检查用户ID格式是否有效（避免连接无效路径）
    // 如果用户ID是纯数字（如 "1"），可能是无效的ID
    if (/^\d+$/.test(userId)) {
      console.warn('[WebSocketService] 用户ID格式可能无效，跳过全局WebSocket初始化:', userId)
      console.warn('[WebSocketService] 提示：全局WebSocket用于系统通知，客服系统使用独立的WebSocket连接')
      return
    }

    // 如果已存在连接，先断开（避免重复连接）
    if (this.client) {
      this.disconnect()
    }

    console.log('[WebSocketService] 初始化全局 WebSocket 连接，用户ID:', userId)
    // 注意：全局WebSocket使用 /ws/{client_id} 路由（用于系统通知等）
    // 客服系统的WebSocket使用 /ws/chat/{group} 路由（用于实时聊天）
    // 两者不冲突，可以同时存在
    // 创建 WebSocket 客户端实例（使用用户ID作为客户端标识）
    this.client = createWebSocketClient(userId, {
      reconnectInterval: 3000,        // 重连间隔3秒
      maxReconnectAttempts: 10,       // 全局连接重试次数更多（10次），因为全局连接更重要
      heartbeatInterval: 30000       // 心跳间隔30秒
    })

    // ============ 连接成功事件 ============
    this.client.onOpen = () => {
      console.log('[WebSocketService] 全局连接成功')
      // 通知所有连接状态监听器：连接已建立
      this.notifyConnectionListeners(true)
    }

    // ============ 连接关闭事件 ============
    this.client.onClose = () => {
      console.log('[WebSocketService] 全局连接关闭')
      // 通知所有连接状态监听器：连接已断开
      this.notifyConnectionListeners(false)
    }

    // ============ 连接错误事件 ============
    this.client.onError = (error) => {
      console.error('[WebSocketService] 连接错误:', error)
      // 通知所有连接状态监听器：连接出现错误
      this.notifyConnectionListeners(false)
    }

    // ============ 接收消息事件 ============
    this.client.onMessage = (data, event) => {
      console.log('[WebSocketService] 收到全局消息:', data)
      // 将消息路由到对应的处理器
      this.handleMessage(data)
    }

    // 开始连接服务器
    this.client.connect()
  }

  /**
   * 断开全局 WebSocket 连接
   * 
   * 说明：
   * - 清理连接对象，释放资源
   * - 通常在用户登出或应用关闭时调用
   */
  disconnect() {
    if (this.client) {
      this.client.disconnect()  // 断开连接
      this.client = null         // 清空引用
    }
  }

  /**
   * 通过全局 WebSocket 连接发送消息
   * 
   * @param {string|object} data - 要发送的消息
   * @returns {boolean} 发送是否成功
   * 
   * 说明：
   * - 只有在连接已建立时才能发送
   * - 如果连接未就绪，返回 false 并打印警告
   */
  send(data) {
    // 检查连接状态：只有已连接才能发送消息
    if (this.client && this.client.isConnected()) {
      return this.client.send(data)
    }
    console.warn('[WebSocketService] 连接未就绪，无法发送消息')
    return false
  }

  /**
   * 处理接收到的消息
   */
  handleMessage(data) {
    // 忽略心跳消息
    if (data === 'ping' || data === 'pong') {
      return
    }

    // 解析消息类型
    let messageType = '*'
    if (typeof data === 'object' && data.type) {
      messageType = data.type
    }

    // 触发对应的处理器
    const handlers = this.messageHandlers.get(messageType) || []
    handlers.forEach(handler => {
      try {
        handler(data)
      } catch (error) {
        console.error('[WebSocketService] 消息处理器错误:', error)
      }
    })

    // 触发通用处理器
    if (messageType !== '*') {
      const generalHandlers = this.messageHandlers.get('*') || []
      generalHandlers.forEach(handler => {
        try {
          handler(data)
        } catch (error) {
          console.error('[WebSocketService] 通用消息处理器错误:', error)
        }
      })
    }
  }

  /**
   * 注册消息类型处理器
   * 
   * @param {string} type - 消息类型（如 'notification', 'chat' 等，'*' 表示所有消息）
   * @param {function} handler - 处理函数，接收消息数据作为参数
   * @returns {function} 取消注册函数，调用后移除该处理器
   * 
   * 使用示例：
   * // 监听系统通知
   * const unsubscribe = websocketService.onMessage('notification', (data) => {
   *   console.log('收到通知:', data)
   * })
   * // 稍后取消订阅
   * unsubscribe()
   */
  onMessage(type, handler) {
    // 如果该消息类型还没有处理器数组，创建一个空数组
    if (!this.messageHandlers.has(type)) {
      this.messageHandlers.set(type, [])
    }
    // 将处理器添加到对应类型的数组中（支持多个处理器）
    this.messageHandlers.get(type).push(handler)

    // 返回取消注册函数（用于清理，防止内存泄漏）
    return () => {
      const handlers = this.messageHandlers.get(type)
      const index = handlers.indexOf(handler)
      if (index > -1) {
        handlers.splice(index, 1)  // 从数组中移除该处理器
      }
    }
  }

  /**
   * 注册连接状态监听器
   * 
   * @param {function} listener - 监听函数，接收 (isConnected: boolean) 参数
   * @returns {function} 取消注册函数
   * 
   * 用途：
   * - 监听连接状态变化（连接/断开）
   * - 更新 UI 状态（如显示连接指示器）
   * - 记录连接日志
   */
  onConnectionChange(listener) {
    // 将监听器添加到数组中
    this.connectionListeners.push(listener)
    
    // 返回取消注册函数
    return () => {
      const index = this.connectionListeners.indexOf(listener)
      if (index > -1) {
        this.connectionListeners.splice(index, 1)  // 从数组中移除
      }
    }
  }

  /**
   * 通知所有连接状态监听器
   * 
   * @param {boolean} isConnected - 当前连接状态（true=已连接，false=已断开）
   * 
   * 说明：
   * - 在连接建立、断开、错误时调用
   * - 遍历所有监听器并触发，捕获异常避免影响其他监听器
   */
  notifyConnectionListeners(isConnected) {
    // 遍历所有监听器并触发
    this.connectionListeners.forEach(listener => {
      try {
        listener(isConnected)  // 调用监听器，传入连接状态
      } catch (error) {
        // 捕获异常，避免一个监听器出错影响其他监听器
        console.error('[WebSocketService] 连接状态监听器错误:', error)
      }
    })
  }

  /**
   * 检查全局 WebSocket 是否已连接
   * 
   * @returns {boolean} true 表示连接已建立且可以通信
   */
  isConnected() {
    return this.client && this.client.isConnected()
  }

  /**
   * 获取连接状态字符串
   * 
   * @returns {string} 状态字符串：'disconnected' | 'connecting' | 'connected' | 'reconnecting'
   */
  getStatus() {
    return this.client ? this.client.getStatus() : 'disconnected'
  }
}

// ============ 创建全局单例 ============
// 整个应用共享同一个 WebSocket 服务实例
// 这样可以：
// 1. 避免重复连接（多个组件共享一个连接）
// 2. 统一管理消息路由（所有消息都经过同一个服务）
// 3. 节省资源（只维护一个 WebSocket 连接）
const websocketService = new WebSocketService()

export default websocketService

